import paho.mqtt.client as mqtt
import json
import time
import random
import logging
import argparse
from datetime import datetime

# 配置日志
logging.basicConfig(
    level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger("DeviceSimulator")

# 数据文件路径
DATA_FILE = "device.json"

# 默认配置
DEFAULT_CONFIG = {
    "broker": "broker.emqx.io",
    "port": 1883,
    "client_id": f"mqtt_client_{int(time.time())}",
    "topic": "/broker/mqtt/Limo",
    "control_topic": "/broker/mqtt/Limo_s",
}

# 设备状态
device_state = {"door": "close", "window": "close", "light": "off"}

# 环境数据
env_data = {"tem": 24.8, "hum": 48.2, "lux": 850.0}  # 温度(°C)  # 湿度(%)  # 光照(lux)

# 功率数据
power_data = {"W": 25.4, "I": 10.8, "U": 230.5}  # 功率(W)  # 电流(A)  # 电压(V)


# 获取当前时间戳 (格式: 2025/05/15-09:13:36)
def get_timestamp():
    return datetime.now().strftime("%Y/%m/%d-%H:%M:%S")


# 保存数据到文件
def save_data_to_file(data):
    try:
        with open(DATA_FILE, "a", encoding="utf-8") as f:
            # 添加时间戳和分隔符，方便区分不同时间的数据
            timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            f.write(f"--- {timestamp} ---\n")
            json.dump(data, f, ensure_ascii=False, indent=2)
            f.write("\n\n")
        logger.info(f"数据已保存到 {DATA_FILE}")
    except Exception as e:
        logger.error(f"保存数据到文件失败: {str(e)}")


# 连接成功回调
def on_connect(client, userdata, flags, rc):
    if rc == 0:
        logger.info(f"MQTT 连接成功")
        # 订阅控制主题
        client.subscribe(userdata["control_topic"])
        logger.info(f"已订阅控制主题: {userdata['control_topic']}")
    else:
        logger.error(f"MQTT 连接失败，错误码: {rc}")


# 接收到消息回调
def on_message(client, userdata, msg):
    payload = msg.payload.decode("utf-8")
    logger.info(f"收到控制消息: {payload}")

    try:
        device, action = payload.split(":", 1)
        device = device.strip().lower()
        action = action.strip().lower()

        if device in device_state:
            if action in ["open", "on", "close", "off"]:
                if device in ["door", "window"]:
                    device_state[device] = "open" if action == "open" else "close"
                else:
                    device_state[device] = "on" if action == "on" else "off"
                logger.info(f"设备 {device} 已设置为 {device_state[device]}")
                
                # 状态变更后发送一次数据
                send_device_data(client, userdata["topic"])
            else:
                logger.warning(f"无效的动作: {action}")
        elif device == "env" and action == "get":
            # 仅在收到env:get命令时发送数据
            send_device_data(client, userdata["topic"])
        else:
            logger.warning(f"未知设备: {device}")

    except ValueError:
        logger.error(f"解析控制命令失败: {payload}")


def send_device_data(client, topic):
    # 随机生成微小波动
    power_data["W"] = round(power_data["W"] + random.uniform(-0.2, 0.2), 1)
    power_data["I"] = round(power_data["I"] + random.uniform(-0.1, 0.1), 1)
    power_data["U"] = round(power_data["U"] + random.uniform(-0.5, 0.5), 1)
    
    env_data["tem"] = round(env_data["tem"] + random.uniform(-0.1, 0.1), 1)
    env_data["hum"] = round(env_data["hum"] + random.uniform(-0.5, 0.5), 1)
    env_data["lux"] = round(env_data["lux"] + random.uniform(-10, 10), 1)

    # 构建完整数据（符合指定格式）
    full_data = {
        "id": f"EMD-{random.randint(10000, 99999)}",  # 随机生成设备ID
        "time": get_timestamp(),
        "power": power_data,
        "env": env_data,
        "status": device_state,
    }
    
    json_data = json.dumps(full_data)
    client.publish(topic, json_data)
    logger.info(f"已发送设备数据: {json_data}")

    # 保存数据到文件
    save_data_to_file(full_data)


def main(config):
    # 创建MQTT客户端
    client = mqtt.Client(client_id=config["client_id"])
    client.user_data_set(config)

    # 设置回调函数
    client.on_connect = on_connect
    client.on_message = on_message

    try:
        client.connect(config["broker"], config["port"], 60)
    except Exception as e:
        logger.error(f"连接MQTT服务器失败: {str(e)}")
        return
    
    # 启动循环，等待消息
    client.loop_forever()


if __name__ == "__main__":
    # 解析命令行参数
    parser = argparse.ArgumentParser(description="设备模拟器")
    parser.add_argument(
        "--broker", help="MQTT代理服务器地址", default=DEFAULT_CONFIG["broker"]
    )
    parser.add_argument(
        "--port", help="MQTT代理服务器端口", type=int, default=DEFAULT_CONFIG["port"]
    )
    parser.add_argument(
        "--client_id", help="MQTT客户端ID", default=DEFAULT_CONFIG["client_id"]
    )
    parser.add_argument(
        "--topic", help="发布数据的主题", default=DEFAULT_CONFIG["topic"]
    )
    parser.add_argument(
        "--control_topic",
        help="订阅控制命令的主题",
        default=DEFAULT_CONFIG["control_topic"],
    )

    args = parser.parse_args()

    # 配置
    config = {
        "broker": args.broker,
        "port": args.port,
        "client_id": args.client_id,
        "topic": args.topic,
        "control_topic": args.control_topic,
    }

    logger.info(f"设备模拟器已启动，配置: {config}")
    main(config)    